#/usr/bin/python
#coding: utf-8 -*-

'''
Script de rÃ©solution du problÃ¨me d'approvisionnement des villes de WOW par les entrepots.
'''

from optparse import OptionParser
import sys, pickle
import logging
from GloutonSolver import *
from RecuitSolver import *
from TabooSolver import *
from GLPKSolver import *


def parseargs():
	parser = OptionParser()
	parser.add_option("-o", "--output", dest="filename",
        	help="write topology to FILE", metavar="FILE")

	parser.add_option("-i", "--import", dest="importF",
        	help="open topology from FILE", metavar="FILE")

	parser.add_option("-e", "--entrepots", dest="entrepots",
		help="Nombre d'emplacements potentiels d'entrepots")
		 
	parser.add_option("-d", "--driver", dest="driver",
        	help="Driver de calcul à employer pour résourdre le problème",
		choices=["enum","glouton", "recuit", "taboo", "genetik", "glpk"])

	parser.add_option("-v", "--villes", dest="villes",
		help="Nombre de villes à servir")

	(options, args) = parser.parse_args()
	return options

class warehouse(object):
	def __init__(self, name = None, capacity = 0, cost = 0):
		self.name = name
		self.capacity = capacity
		self.original_capacity = capacity
		self.cost = cost
	def is_empty(self):
		if (self.capacity == 0):
			return True
		else:
			return False
	def taking(self, value = 1):
		if (value <= self.capacity):
			self.capacity -= value
		else:
			value = self.capacity
			self.capacity = 0
		return value
		
class city(object):
	def __init__(self, name = None, needs = 0):
		self.name = name
		self.original_needs = needs
		self.current_needs = needs
	def satisfaction(self):
		return (((self.original_needs - self.current_needs)/self.original_needs) * 100)
	def giving(self, value = 0):
		if self.current_needs - value >= 0:
			self.current_needs = self.current_needs - value
			return self.current_needs
		else:
			self.current_needs = 0
			return self.current_needs - value

class road(object):
	def __init__(self, city = None, warehouse = None, cost = 0):
		self.city = city
		self.warehouse = warehouse
		self.cost = cost
		self.transit = 0

class topology(object):
	def __init__(self):
		self.warehouses 		= []
		self.cities 			= []
		self.roads 			= []
		self.constructedWarehouses 	= []
		self.tracer			= []

	def save(self, filename):
		output = open(filename, 'w')
		pickle.dump(self, output)
		output.close
		
	def load(self, filename):
		pkl_file = open(filename, 'r')
		data = pickle.load(pkl_file)
		pkl_file.close()
		return data

	def construct(self, opts):
		for i in xrange(int(opts.entrepots)):
			print("Nom de l'emplacement: ")
			emplacement = sys.stdin.readline()
			print("Capacite: ")
			capacite = int(sys.stdin.readline())
			print("Cout: ")
			cout = int(sys.stdin.readline())
			whouse = warehouse(emplacement, capacite, cout)
			self.warehouses.append(whouse)

		for i in xrange(int(opts.villes)):
			print("Nom de la ville: ")
			nom = sys.stdin.readline()
			print("Besoins: ")
			besoin = int(sys.stdin.readline())
			mycity = city(nom, besoin)
			self.cities.append(mycity)
			
		for x in self.warehouses:
			for y in self.cities:
				print("Cout de la route de " + x.name + " a " + y.name)
				cost = int(sys.stdin.readline())
				myroad = road(y.name, x.name, cost)
				self.roads.append(myroad)
				
	def show(self):
		print("*******************************")
		print("*Récapitulatif de la Topologie*")
		print("*******************************")
		for x in self.roads:
			print("De " +  x.city + " a " + x.warehouse + " coute " +str(x.cost))
			
	def transit(self, origine = None, destination = None, value = 0):
		#+n transit sur la route
		#+n valeur bouffe
		#-n entrepot
		logging.debug('Transit de ' + str(value) + ' unitÃ©s ' + ' de ' + origine + ' Ã  ' + destination)

		for i in self.warehouses:
			if i.name == origine:
				obtained = i.taking(value)
				if obtained != value:
					logging.debug('Entrepot ' + origine + ' trop sollicité, ' + str(obtained) +' obtenus au lieu de ' + str(value) + ' demandÃ©s')
					value = obtained

		for j in self.cities:
			if j.name == destination:
				retour = j.giving(value)
				if retour < 0:
					for i in self.warehouses:
						if i.name == origine:
							i.capacity -=  retour
							
		for k in self.roads:
			if k.warehouse == origine and k.city == destination:
				k.transit += value
		return value

	def calculate(self):
		total = 0
		for i in self.constructedWarehouses:
			print("Un entrepot est construit Ã  " + i.name)
			logging.debug("Un entrepot est construit Ã  " + i.name)
			total += i.cost
		for j in self.roads:
			print(str(j.transit) + " ont transitÃ© sur la route de " + j.warehouse + " Ã  " + j.city)
			logging.debug(str(j.transit) + " ont transitÃ© sur la route de " + j.warehouse + " Ã  " + j.city)
			total += j.cost * j.transit
			return total
	
	def createWarehouse(self, name = None):
		for i in self.warehouses:
			if i.name == name:
				selected = i
		self.constructedWarehouses.append(selected)

def main():
	opts = parseargs()
	topo = topology()

	if opts.filename is not None:
		sortie = opts.filename
		if opts.entrepots is None:
			print("Nombre d'entrepots obligatoire")
			return(1)
		if opts.villes is None:
			print("Nombre de villes obligatoire")
			return(1)
		else:
			topo.construct(opts)
			topo.save(opts.filename)
			topo.show()
	elif opts.importF is not None:
		sortie = opts.importF
		topo = topo.load(opts.importF)
		#topo.show()
		
	if opts.driver == "enum":
		sortie += ".enum.out"
		logging.basicConfig(filename=sortie,level=logging.DEBUG,)
		logging.warning('Lancement du solveur Ã©numÃ©ration totale')
		mysolver = solver(topo)
		result = mysolver.enum_total()
		
	elif opts.driver == "glouton":
		sortie += ".glouton.out"
		logging.basicConfig(filename=sortie,level=logging.DEBUG,)
		logging.warning('Lancement du solveur glouton')
		GloutonSolver.GloutonSolver(topo)

	elif opts.driver == "recuit":
		sortie += ".recuit.out"
		logging.basicConfig(filename=sortie,level=logging.DEBUG,)
		logging.warning('Lancement du solveur recuit')
		RecuitSolver(topo)
		
	elif opts.driver == "taboo":
		sortie += ".taboo.out"
		logging.basicConfig(filename=sortie,level=logging.DEBUG,)
		logging.warning('Lancement du solveur taboo')
		result = TabooSolver(topo)
		
	elif opts.driver == "genetik":
		sortie += ".genetik.out"
		logging.basicConfig(filename=sortie,level=logging.DEBUG,)
		logging.warning('Lancement du solveur')
		mysolver = solver(topo)
		result = mysolver.genetik()
		
	elif opts.driver == "glpk":
		sortie += ".glpk.out"
		logging.basicConfig(filename=sortie,level=logging.DEBUG,)
		logging.warning('Lancement du solveur glpk')
		result = GLPKSolver(topo)

	else:
		print("Routines de fichiers obligatoires (-i ou -o)")
		print("Consultez l'aide avec l'option -h ou --help")

class solver(object):
	def __init__(self, Topo = None):
		self.topology = Topo
		self.total_cost = 0

	def enum_total(self, topology):
		logging.warning('Ceci est un message d\'avertissement Ã  utiliser pour le lancement ou la fin de la mÃ©thode')
		logging.info('Ceci est un message d\'info Ã  utiliser Ã  chaque lancement de boucle ou changement de phase dans la mÃ©thode')
		logging.debug('Ceci est un message de dÃ©bug, Ã  utiliser Ã  chaque itÃ©ration de la mÃ©thode')
		#constuire l'entrepot Toto selon ses caractÃ©ristiques dÃ©finies dans le tableau de Warehouses
		#topology.createWarehouse(Toto)
		#faire transiter N Ã©lÃ©ments de l'entrepot X Ã  la ville Y:
		#topology.transit(X, Y, N)
		#Calculer le cout total du choix de la topologie dÃ©crite par les diffÃ©rents createWarehouses successifs:
		#resultat = topology.calculate()
		pass


	def genetik(self, topology):
		logging.warning('Ceci est un message d\'avertissement Ã  utiliser pour le lancement ou la fin de la mÃ©thode')
		logging.info('Ceci est un message d\'info Ã  utiliser Ã  chaque lancement de boucle ou changement de phase dans la mÃ©thode')
		logging.debug('Ceci est un message de dÃ©bug, Ã  utiliser Ã  chaque itÃ©ration de la mÃ©thode')
		pass



if __name__ == "__main__":
	main()

